Return to start page

Core/Interface/Struct Third Person Camera.j

Code

		
1			/// @author Opossum
2 library AStructCoreInterfaceThirdPersonCamera requires AStructCoreInterfaceArrowKeys
3
4 /**
5 * Adds a dynamic third person camera to the game.
6 * Its main purpose is to enable the user a highly configurable camera without the usual
7 * limitations of third person cameras. Using this camera you can basically use any kind
8 * of terrain on your map without caring about the cam falling below the terrain or
9 * clipping parts of the terrain.
10 * Note that you have to initialize @struct AArrowKeys before initializing this struct.
11 * @author Opossum
12 * @author Tamino Dauth
13 * @link http://www.wc3c.net/showthread.php?t=104786
14 */
15 struct AThirdPersonCamera
16 private static constant real distanceAoaMin = -15.0
17 private static constant real distanceDistanceMin = 300.0
18 private static constant real distanceAoaMax = -65.0
19 private static constant real distanceDistanceMax = 500.0
20 private static constant real offsetAoaMin = -35.0
21 private static constant real offsetOffsetMin = 0.0
22 private static constant real offsetAoaMax = -70.0
23 private static constant real offsetOffsetMax = 150.0
24 private static constant real zOffset = 100.0
25 private static constant real timeout = 0.1
26 private static constant real terrainSampling = 32
27 private static constant real panDuration = 0.5
28 private static constant real angleAboveTerrain = 15.0
29 private static constant real defaultAoa = -20.0
30 private static constant real defaultRot = 0.0
31 private static constant real fieldOfView = 120.0
32 private static constant real farZ = 5000.0
33 private static constant real cliffDistance = 500.0
34 //key settings
35 private static constant boolean inverted = false
36 private static constant real minAoa = -65.0
37 private static constant real maxAoa = 0.0
38 private static constant real maxRot = 105.0
39 private static constant real aoaInterval = 3.0
40 private static constant real rotInterval = 7.5
41 //static start members
42 private static boolean m_useArrowKeys
43 //static members
44 private static thistype array m_playerThirdPersonCamera[12] /// @todo bj_MAX_PLAYERS
45 private static location m_location
46 private static real m_distanceM
47 private static real m_distanceT
48 private static real m_offsetM
49 private static real m_offsetT
50 private static timer m_timer
51 //dynamic members
52 private real m_camAoa
53 private real m_camRot
54 //start members
55 private player m_player
56 //members
57 private unit m_unit
58 private boolean m_isEnabled
59 private timer m_firstPan
60
61 //dynamic members
62
63 public method setCamAoa takes real camAoa returns nothing
64 set this.m_camAoa = camAoa
65 endmethod
66
67 public method camAoa takes nothing returns real
68 return this.m_camAoa
69 endmethod
70
71 public method setCamRot takes real camRot returns nothing
72 set this.m_camRot = camRot
73 endmethod
74
75 public method camRot takes nothing returns real
76 return this.m_camRot
77 endmethod
78
79 //start members
80
81 public method player takes nothing returns player
82 return this.m_player
83 endmethod
84
85 //members
86
87 public method unit takes nothing returns unit
88 return this.m_unit
89 endmethod
90
91 public method isEnabled takes nothing returns boolean
92 return this.m_isEnabled
93 endmethod
94
95 //methods
96
97 public method enable takes unit whichUnit, real firstPan returns nothing
98 set this.m_unit = whichUnit
99 set this.m_isEnabled = true
100 call TimerStart(this.m_firstPan, firstPan, false, null)
101 if (GetLocalPlayer() == this.m_player) then
102 call StopCamera()
103 if (whichUnit != null) then
104 call this.applyCam(firstPan)
105 endif
106 endif
107 endmethod
108
109 public method disable takes nothing returns nothing
110 if (TimerGetRemaining(this.m_firstPan) > 0.0) then
111 call PauseTimer(this.m_firstPan)
112 endif
113 set this.m_unit = null
114 set this.m_isEnabled = false
115 endmethod
116
117 public method pause takes nothing returns nothing
118 call PauseTimer(this.m_firstPan)
119 set this.m_isEnabled = false
120 endmethod
121
122 public method resume takes nothing returns nothing
123 call ResumeTimer(this.m_firstPan)
124 set this.m_isEnabled = true
125 endmethod
126
127 public method resetCamAoa takes nothing returns nothing
128 set this.m_camAoa = thistype.defaultAoa
129 endmethod
130
131 public method resetCamRot takes nothing returns nothing
132 set this.m_camRot = thistype.defaultRot
133 endmethod
134
135 private method applyCam takes real duration returns nothing
136 local real aoa = GetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK) - 2 * bj_PI
137 local real offset = thistype.interpolateOffset(aoa)
138 local real newaoa
139 local real maxd
140 local real tarz
141 local real newx
142 local real newy
143 local real newm
144 local real maxm = -1
145 local real r = thistype.terrainSampling
146 local real dx
147 local real dy
148
149 if (thistype.m_useArrowKeys) then
150 if (thistype.inverted) then
151 set this.m_camRot = thistype.cappedReal(this.m_camRot + (AArrowKeys.playerArrowKeys(this.m_player).horizontal() + AArrowKeys.playerArrowKeys(this.m_player).horizontalQuickPress()) * thistype.rotInterval, -thistype.maxRot, thistype.maxRot)
152 else
153 set this.m_camRot = thistype.cappedReal(this.m_camRot - (AArrowKeys.playerArrowKeys(this.m_player).horizontal() + AArrowKeys.playerArrowKeys(this.m_player).horizontalQuickPress()) * thistype.rotInterval, -thistype.maxRot, thistype.maxRot)
154 endif
155 call AArrowKeys.playerArrowKeys(this.m_player).setHorizontalQuickPress(0)
156 set this.m_camAoa = thistype.cappedReal(this.m_camAoa - (AArrowKeys.playerArrowKeys(this.m_player).vertical() + AArrowKeys.playerArrowKeys(this.m_player).verticalQuickPress()) * thistype.aoaInterval, thistype.minAoa, thistype.maxAoa)
157 call AArrowKeys.playerArrowKeys(this.m_player).setVerticalQuickPress(0)
158 endif
159
160 call SetCameraField(CAMERA_FIELD_ROTATION, GetUnitFacing(this.m_unit) + this.m_camRot, duration)
161 call SetCameraField(CAMERA_FIELD_FIELD_OF_VIEW, thistype.fieldOfView, duration)
162 call SetCameraField(CAMERA_FIELD_FARZ, thistype.farZ, duration)
163 call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, thistype.interpolateDistance(aoa), duration)
164
165 call PanCameraToTimed(GetUnitX(this.m_unit) + offset * Cos(bj_DEGTORAD*GetUnitFacing(this.m_unit)), GetUnitY(this.m_unit) + offset * Sin(bj_DEGTORAD*GetUnitFacing(this.m_unit)), duration)
166
167 set newx = GetCameraTargetPositionX()
168 set newy = GetCameraTargetPositionY()
169 set maxd = thistype.cliffDistance + GetCameraField(CAMERA_FIELD_TARGET_DISTANCE)
170 set dx = -Cos(GetCameraField(CAMERA_FIELD_ROTATION))*r
171 set dy = -Sin(GetCameraField(CAMERA_FIELD_ROTATION))*r
172
173 call MoveLocation(thistype.m_location, newx, newy)
174 set tarz = GetCameraTargetPositionZ()
175 call SetCameraField(CAMERA_FIELD_ZOFFSET, GetCameraField(CAMERA_FIELD_ZOFFSET) + GetLocationZ(thistype.m_location) + thistype.zOffset + GetUnitFlyHeight(this.m_unit) - tarz, duration)
176
177 loop
178 exitwhen (r > maxd)
179 set newx = newx + dx
180 set newy = newy + dy
181 call MoveLocation(thistype.m_location, newx, newy)
182 set newm = (GetLocationZ(thistype.m_location) - tarz) / r
183 if (newm > maxm) then
184 set maxm = newm
185 endif
186 set r = r + thistype.terrainSampling
187 endloop
188 set newaoa = - Atan(maxm) * bj_RADTODEG - thistype.angleAboveTerrain
189 if (this.m_camAoa < newaoa) then
190 set newaoa = this.m_camAoa
191 endif
192 call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, newaoa, duration)
193 endmethod
194
195 private static method create takes player usedPlayer returns thistype
196 local thistype this = thistype.allocate()
197 //dynamic members
198 set this.m_camAoa = thistype.defaultAoa
199 set this.m_camRot = thistype.defaultRot
200 //start members
201 set this.m_player = usedPlayer
202 //members
203 set this.m_unit = null
204 set this.m_firstPan = CreateTimer()
205 return this
206 endmethod
207
208 public method onDestroy takes nothing returns nothing
209 //start members
210 set this.m_player = null
211 //members
212 set this.m_unit = null
213 call PauseTimer(this.m_firstPan)
214 call DestroyTimer(this.m_firstPan)
215 set this.m_firstPan = null
216 endmethod
217
218 private static method timerFunctionRefresh takes nothing returns nothing
219 local player localPlayer = GetLocalPlayer()
220 local integer playerId = GetPlayerId(localPlayer)
221 if (thistype.m_playerThirdPersonCamera[playerId] != 0 and thistype.m_playerThirdPersonCamera[playerId].m_isEnabled) then
222 if (TimerGetRemaining(thistype.m_playerThirdPersonCamera[playerId].m_firstPan) <= thistype.panDuration) then
223 call thistype.m_playerThirdPersonCamera[playerId].applyCam(thistype.panDuration)
224 else
225 call thistype.m_playerThirdPersonCamera[playerId].applyCam(TimerGetRemaining(thistype.m_playerThirdPersonCamera[playerId].m_firstPan))
226 endif
227 endif
228 endmethod
229
230 public static method init takes boolean useArrowKeys returns nothing
231 //static start members
232 set thistype.m_useArrowKeys = useArrowKeys
233 //static members
234 set thistype.m_location = Location(0,0)
235 set thistype.m_distanceM = (thistype.distanceDistanceMax-thistype.distanceDistanceMin)/((thistype.distanceAoaMax - thistype.distanceAoaMin)*bj_DEGTORAD)
236 set thistype.m_distanceT = thistype.distanceDistanceMin-thistype.distanceAoaMin*bj_DEGTORAD*thistype.m_distanceM
237 set thistype.m_offsetM = (thistype.offsetOffsetMax-thistype.offsetOffsetMin)/((thistype.offsetAoaMax-thistype.offsetAoaMin)*bj_DEGTORAD)
238 set thistype.m_offsetT = thistype.offsetOffsetMin-thistype.offsetAoaMin*bj_DEGTORAD* thistype.m_offsetM
239 set thistype.m_timer = CreateTimer()
240 call TimerStart(thistype.m_timer, thistype.timeout, true, function thistype.timerFunctionRefresh)
241 endmethod
242
243 public static method cleanUp takes nothing returns nothing
244 call PauseTimer(thistype.m_timer)
245 call RemoveLocation(thistype.m_location)
246 set thistype.m_location = null
247 call DestroyTimer(thistype.m_timer)
248 set thistype.m_timer = null
249 endmethod
250
251 public static method playerThirdPersonCamera takes player user returns thistype
252 if (thistype.m_playerThirdPersonCamera[GetPlayerId(user)] == 0) then
253 set thistype.m_playerThirdPersonCamera[GetPlayerId(user)] = thistype.create(user)
254 endif
255 return thistype.m_playerThirdPersonCamera[GetPlayerId(user)]
256 endmethod
257
258 /// Functions for distance and offset. These are linear mathematical functions y = mx+t.
259 private static method interpolateDistance takes real angleOfAttack returns real
260 if (angleOfAttack <= thistype.distanceAoaMax * bj_DEGTORAD) then
261 return thistype.distanceDistanceMax
262 elseif (angleOfAttack >= thistype.distanceAoaMin * bj_DEGTORAD) then
263 return thistype.distanceDistanceMin
264 endif
265 return thistype.m_distanceM * angleOfAttack + thistype.m_distanceT
266 endmethod
267
268 private static method interpolateOffset takes real angleOfAttack returns real
269 if (angleOfAttack <= thistype.offsetAoaMax * bj_DEGTORAD) then
270 return thistype.offsetOffsetMax
271 elseif (angleOfAttack >= thistype.offsetAoaMin * bj_DEGTORAD) then
272 return thistype.offsetOffsetMin
273 endif
274 return thistype.m_offsetM * angleOfAttack + thistype.m_offsetT
275 endmethod
276
277 private static method cappedReal takes real r, real lowBound, real highBound returns real
278 if r < lowBound then
279 return lowBound
280 elseif r > highBound then
281 return highBound
282 endif
283 return r
284 endmethod
285 endstruct
286
287 endlibrary